//************************************************************************
//Developed by Guo Ming Li 2009/2010
//Source code:
//  The source code may be freely modified or used but this credit section may not be removed 
//  The original author must be notified of any modifications plus a copy of 
//  the changed source code
//Contact info: mailto://gming.li@gmail.com
//************************************************************************
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using Microsoft.BizTalk.ExplorerOM;
using Microsoft.BizTalk.ApplicationDeployment;
using Microsoft.BizTalk.Deployment.Binding;
using System.Reflection;
using System.IO;
using System.Data.SqlClient;
using Microsoft.BizTalk.Deployment;
using System.Xml;

namespace GML.BizTalk.OperationManager.Library
{
    public class BtsBindingInfo
    {

        public static bool Import
            (
            Nullable<bool> isGroupLevel, 
            string btsDbServerName, string btsMgntDbName, string sBtsAppName,
            string bindingFilesource
            )
        {
            try
            {
                bool flag = (isGroupLevel == null ? false : true); 
                bool blnAppNameSpecified = (string.IsNullOrEmpty(sBtsAppName) ? false : true);
                string str = sBtsAppName; 
                if (flag && !string.IsNullOrEmpty(str))
                {
                    throw new ArgumentException("Multiple Scope Specified");
                }
                string bindingsFile = bindingFilesource; 
                string server = btsDbServerName; 
                string database = btsMgntDbName; 
                
                int warnings = 0;
                string message = null;
                string connectionString = Helper.GetConnectionString(server, database);
                using (DeployerComponent component = new DeployerComponent())
                {
                    switch (component.ImportBindingWithValidation(connectionString, bindingsFile, str, false, ref message))
                    {
                        case ImportBindingError.Failed:
                            throw new Exception(message);

                        case ImportBindingError.SucceededWithWarning:
                            break;

                        default:
                            break;
                    }
                    warnings++;
                }
                if (!flag)
                {
                    message = "Import Bindings Success";
                }
                else
                {
                    BtsCatalogExplorer explorer = new BtsCatalogExplorer();
                    explorer.ConnectionString = connectionString;
                    message = "Import Bindings Success for Group";
                }
                str = null;
                bindingsFile = null;
                server = null;
                database = null;
                message = null;
                connectionString = null;
                return true;
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + Environment.NewLine + exception.StackTrace);
                Logger.doLog(Guid.NewGuid().ToString(), exception.Message, Logger.ServerityLevel.ERROR);
                Logger.doLog(Guid.NewGuid().ToString(), exception.StackTrace, Logger.ServerityLevel.ERROR);

                throw exception;
            }
        }

        public static bool Export(
            bool isGroupLevel, bool isGlobalParties, bool isExportForEntireApplication,
            string btsDbServerName, string btsMgntDbName, string sBtsAppName,
            bool isIncludeSendPortInfo, bool isIncludeReceivePortInfo,
            string[] sAssemblyLUIDs, string sDestinationUrl)
        {

            BindingInfo bindingWithApp = new BindingInfo();
            BindingInfo bindingWitoutApp = new BindingInfo();
            BindingInfo newBinding = new BindingInfo();
            ModuleRefCollection oMRC = new ModuleRefCollection();
            XmlDocument xBindingFile = new XmlDocument();

            string sDestination = sDestinationUrl;
            try
            {
                if (sAssemblyLUIDs != null && (isIncludeSendPortInfo || isIncludeReceivePortInfo))
                {
                    bindingWitoutApp = GetBindingInfo(isGroupLevel, isGlobalParties, btsDbServerName, btsMgntDbName, null, sAssemblyLUIDs, ref sDestination);
                    bindingWithApp = GetBindingInfo(isGroupLevel, isGlobalParties, btsDbServerName, btsMgntDbName, sBtsAppName, null, ref sDestination);

                    foreach (ModuleRef mr in bindingWithApp.ModuleRefCollection)
                    {
                        if (mr.Name.Equals("[Application:" + sBtsAppName + "]"))
                        {
                            oMRC.Add(mr);
                            break;
                        }
                    }

                    foreach (ModuleRef mr in bindingWitoutApp.ModuleRefCollection)
                    {
                        oMRC.Add(mr);
                    }

                    bindingWithApp.ModuleRefCollection = oMRC;
                    bindingWithApp.SaveXml(sDestination);


                }
                else
                {
                    bindingWithApp = GetBindingInfo(
                            isGroupLevel, isGlobalParties, btsDbServerName, btsMgntDbName,
                            (isExportForEntireApplication) ? sBtsAppName : null,
                            sAssemblyLUIDs, ref sDestination);
                    bindingWithApp.SaveXml(sDestination);
                }

                if (!isIncludeSendPortInfo || !isIncludeReceivePortInfo)
                {
                    xBindingFile.Load(sDestination);
                    if (xBindingFile != null && !isIncludeSendPortInfo)
                    {
                        XmlNode childNode = xBindingFile.SelectSingleNode("/BindingInfo/SendPortCollection");
                        childNode.ParentNode.RemoveChild(childNode);
                    }
                    if (xBindingFile != null && !isIncludeReceivePortInfo)
                    {
                        XmlNode childNode = xBindingFile.SelectSingleNode("/BindingInfo/ReceivePortCollection");
                        childNode.ParentNode.RemoveChild(childNode);
                    }
                    xBindingFile.Save(sDestination);
                    //XmlTextWriter xmlTextWriter = new XmlTextWriter(sDestination, Encoding.UTF8);
                    //xmlTextWriter.WriteRaw(xBindingFile.OuterXml);
                }


                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
                Logger.doLog(Guid.NewGuid().ToString(), ex.Message, Logger.ServerityLevel.ERROR);
                Logger.doLog(Guid.NewGuid().ToString(), ex.StackTrace, Logger.ServerityLevel.ERROR);
                throw ex;
            }
            finally
            {
                bindingWithApp = null;
                bindingWitoutApp = null;
                newBinding = null;
                oMRC = null;
            }

        }

        public static void R2(string btsDbServerName, string btsMgntDbName, string sBtsAppName)
        {

            BindingInfo info = null;
            BindingParameters bindingParameters = null;
            try
            {
                using (SqlConnection sqlConnection = new SqlConnection(Helper.GetConnectionString(btsDbServerName, btsMgntDbName)))
                {
                    info = new BindingInfo();
                    bindingParameters = new BindingParameters(new Version(info.Version));
                    bindingParameters.BindingItems = BindingParameters.BindingItemTypes.All;
                    bindingParameters.BindingActions = BindingParameters.BindingActionTypes.Unbind;
                    bindingParameters.BindingScope = BindingParameters.BindingScopeType.Application;
                    bindingParameters.BindingSetState = BindingParameters.BindingSetStateType.UseServiceState;
                    info.Select(sqlConnection, bindingParameters);
                    info.Update(sqlConnection, bindingParameters, sBtsAppName);
                }

            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message + Environment.NewLine + e.StackTrace);
                Logger.doLog(Guid.NewGuid().ToString(), e.Message, Logger.ServerityLevel.ERROR);
                Logger.doLog(Guid.NewGuid().ToString(), e.StackTrace, Logger.ServerityLevel.ERROR);
            }
            finally
            {
                bindingParameters = null;
                info = null;
            }
        }


        public static BindingInfo GetBindingInfo(
            bool isGroupLevel, bool isGlobalParties, 
            string btsDbServerName, string btsMgntDbName, string sBtsAppName, 
            string [] sAssemblyLUIDs, ref string sDestinationUrl)
        {
            BindingInfo info = null;
            try
            {
                sDestinationUrl = Path.GetFullPath(sDestinationUrl);
                if (
                    ((!isGroupLevel || isGlobalParties)
                        ||
                        ((sAssemblyLUIDs != null) || (sBtsAppName != null))
                   )
                   &&
                   ((
                            (isGroupLevel || (sAssemblyLUIDs == null))
                            || (sBtsAppName != null)
                        )
                        &&
                        (
                            (isGroupLevel || (sAssemblyLUIDs != null))
                            ||
                            (sBtsAppName == null)
                        )
                    )
                )
                {
                    throw new ArgumentException("Invalid argument combination.");
                }
                SqlConnection sqlConnection = new SqlConnection(Helper.GetConnectionString(btsDbServerName, btsMgntDbName));
                info = new BindingInfo();
                BindingParameters bindingParameters = new BindingParameters(new Version(info.Version));
                bindingParameters.BindingItems = BindingParameters.BindingItemTypes.All;
                if (isGroupLevel)
                {
                    bindingParameters.BindingScope = BindingParameters.BindingScopeType.Group;
                }
                else if (sAssemblyLUIDs != null)
                {

                    foreach (string sAssemblyLUID in sAssemblyLUIDs)
                    {
                        bindingParameters.BindingScope = BindingParameters.BindingScopeType.None;
                        AssemblyName name = new AssemblyName(sAssemblyLUID);
                        string culture = (((name.CultureInfo != null) && (name.CultureInfo.Name != null)) && (name.CultureInfo.Name.Length > 0)) ? name.CultureInfo.Name : "neutral";
                        string token = Helper.ByteArrayToHexString(name.GetPublicKeyToken());
                        info.AddModuleRef(name.Name, name.Version.ToString(), culture, token);
                    }
                }
                else if (sBtsAppName != null)
                {
                    bindingParameters.BindingScope = BindingParameters.BindingScopeType.Application;
                    info.AddApplicationRef(sqlConnection, sBtsAppName);
                }
                if (isGlobalParties && !isGroupLevel)
                {
                    bindingParameters.IncludeGlobalParty = true;
                }
                info.Select(sqlConnection, bindingParameters);
                sDestinationUrl = Path.GetFullPath(sDestinationUrl);
                string directoryName = Path.GetDirectoryName(sDestinationUrl);
                if (!Directory.Exists(directoryName))
                {
                    Directory.CreateDirectory(directoryName);
                }
                info.ReceivePortCollection = null;
                info.SendPortCollection = null;
                return info;
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message + Environment.NewLine + e.StackTrace);
                Logger.doLog(Guid.NewGuid().ToString(), e.Message, Logger.ServerityLevel.ERROR);
                Logger.doLog(Guid.NewGuid().ToString(), e.StackTrace, Logger.ServerityLevel.ERROR);
                throw e;
            }
        }

        public static void RemoveAll(string btsDbServerName, string btsMgntDbName, string sBtsAppName)
        {
            BtsCatalogExplorer catalog = new BtsCatalogExplorer();
            catalog.ConnectionString = Helper.GetConnectionString(btsDbServerName, btsMgntDbName);
            Microsoft.BizTalk.ExplorerOM.Application btsApp = null;
            try
            {
                Microsoft.BizTalk.ExplorerOM.ApplicationCollection applications = catalog.Applications;
                foreach (Microsoft.BizTalk.ExplorerOM.Application application in applications)
                {
                    if (application.Name.Equals(sBtsAppName))
                    {
                        btsApp = application;
                    }
                }
                
                //stop the application first
                GML.BizTalk.OperationManager.Library.Applications.Stop(sBtsAppName, btsDbServerName, btsMgntDbName);

                catalog.SaveChanges();

                GML.BizTalk.OperationManager.Library.OrchestrationStateManagement.RemoveAllOrchestrationBindings(btsDbServerName, btsMgntDbName, sBtsAppName);

                GML.BizTalk.OperationManager.Library.ReceivePorts.DeleteAllReceivePorts(btsDbServerName, btsMgntDbName, sBtsAppName);

                GML.BizTalk.OperationManager.Library.SendPortGroups.DeleteSendPortGroups(btsDbServerName, btsMgntDbName, sBtsAppName);

                GML.BizTalk.OperationManager.Library.SendPorts.DeleteSendPorts(btsDbServerName, btsMgntDbName, sBtsAppName);

            }
            catch (Exception e)
            {
                catalog.DiscardChanges();
                System.Diagnostics.Debug.WriteLine(e.Message + Environment.NewLine + e.StackTrace);
                Logger.doLog(Guid.NewGuid().ToString(), e.Message, Logger.ServerityLevel.ERROR);
                Logger.doLog(Guid.NewGuid().ToString(), e.StackTrace, Logger.ServerityLevel.ERROR);
                throw e;
            }
        }
    }
}
